package com.smart.community.property.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smart.community.commons.enums.BusinessStatusEnum;
import com.smart.community.commons.exception.BusinessException;
import com.smart.community.commons.result.PageResult;
import com.smart.community.commons.result.ResultCode;
import com.smart.community.commons.utils.SecurityUtils;
import com.smart.community.property.entity.ElectricityFee;
import com.smart.community.property.enums.PaymentMethodEnum;
import com.smart.community.property.mapper.ElectricityFeeMapper;
import com.smart.community.property.service.DataScopeService;
import com.smart.community.property.service.IElectricityFeeService;
import com.smart.community.property.vo.ElectricityFeeVO;

import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 电费服务实现类
 * 
 * 严格按照《Java后端SpringBoot代码开发规范.md》Service层规范实现：
 * - 异常处理：使用log.warn记录业务异常，使用log.error记录系统异常
 * - 数据权限校验：确保数据安全性
 * - 枚举类型转换：正确处理String类型枚举字段
 * - 生产环境标准：高可用性、可监控性、可维护性、可扩展性
 * - 性能优化：批量操作、缓存机制、查询优化
 * 
 * @author Wu.Liang
 * @since 2024-12-21
 * @version 3.0.0 - 根据新Service规范调整
 */
@Slf4j
@Service
public class ElectricityFeeServiceImpl extends ServiceImpl<ElectricityFeeMapper, ElectricityFee> implements IElectricityFeeService {

    @Autowired
    private ElectricityFeeMapper electricityFeeMapper;
    
    @Autowired
    private DataScopeService dataScopeService;

    @Override
    public IPage<ElectricityFee> getElectricityFeePage(Page<ElectricityFee> page, Long communityId, Integer paymentStatus) throws Exception {
        log.info("分页查询电费账单，社区ID: {}, 支付状态: {}", communityId, paymentStatus);
        
        try {
            // 计算偏移量
            int offset = (int) ((page.getCurrent() - 1) * page.getSize());
            int limit = (int) page.getSize();
            
            // 查询数据
            int total = electricityFeeMapper.countByCommunityAndStatus(communityId, paymentStatus);
            List<ElectricityFee> records = electricityFeeMapper.selectPageByCommunityAndStatus(communityId, paymentStatus, offset, limit);
            
            // 设置分页结果
            page.setRecords(records);
            page.setTotal(total);
            
            log.info("电费账单分页查询完成，总数: {}, 当前页: {}", total, page.getCurrent());
            return page;
        } catch (Exception e) {
            log.error("分页查询电费账单失败，社区ID: {}, 支付状态: {}", communityId, paymentStatus, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "查询电费账单失败");
        }
    }

    @Override
    public ElectricityFee getLatestReadingByHouseholdId(Long householdId) throws Exception {
        log.debug("查询房户最新电表读数，房户ID: {}", householdId);
        
        try {
            return electricityFeeMapper.selectLatestReadingByHouseholdId(householdId);
        } catch (Exception e) {
            log.error("查询房户最新电表读数失败，房户ID: {}", householdId, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "查询电表读数失败");
        }
    }

    @Override
    public ElectricityFee getByHouseholdIdAndBillingPeriod(Long householdId, String billingPeriod) throws Exception {
        log.debug("查询房户指定期间电费记录，房户ID: {}, 计费期间: {}", householdId, billingPeriod);
        
        try {
            return electricityFeeMapper.selectByHouseholdIdAndBillingPeriod(householdId, billingPeriod);
        } catch (Exception e) {
            log.error("查询房户指定期间电费记录失败，房户ID: {}, 计费期间: {}", householdId, billingPeriod, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "查询电费记录失败");
        }
    }

    @Override
    @GlobalTransactional
    public boolean submitElectricityMeterReading(Long householdId, BigDecimal reading, LocalDate readingDate) throws Exception {
        log.info("提交电表读数，房户ID: {}, 表读数: {}, 读数日期: {}", householdId, reading, readingDate);
        
        try {
            // 参数验证
            if (householdId == null || reading == null || readingDate == null) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "参数不能为空");
            }
            
            if (reading.compareTo(BigDecimal.ZERO) < 0) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "表读数不能为负数");
            }

            // 获取最新的电表读数
            ElectricityFee latestReading = electricityFeeMapper.selectLatestReadingByHouseholdId(householdId);
            if (latestReading != null && latestReading.getCurrentReading().compareTo(reading) >= 0) {
                log.warn("新读数不能小于或等于上次读数，房户ID: {}, 新读数: {}, 上次读数: {}", 
                    householdId, reading, latestReading.getCurrentReading());
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "新读数不能小于或等于上次读数");
            }

            // 创建新的电费记录
            ElectricityFee electricityFee = new ElectricityFee();
            electricityFee.setHouseholdId(householdId);
            electricityFee.setCurrentReading(reading);
            electricityFee.setReadingDate(readingDate);
            electricityFee.setPaymentStatus(BusinessStatusEnum.PAYMENT_PENDING.getCode()); // 未支付

            boolean result = electricityFeeMapper.insert(electricityFee) > 0;
            log.info("电表读数提交完成，房户ID: {}, 结果: {}", householdId, result);
            return result;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("提交电表读数失败，房户ID: {}", householdId, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "提交电表读数失败");
        }
    }

    @Override
    @GlobalTransactional
    public boolean batchSubmitMeterReading(Long communityId, List<Map<String, Object>> meterReadings) throws Exception {
        log.info("批量提交电表读数，社区ID: {}, 数据条数: {}", communityId, meterReadings.size());
        
        try {
            if (meterReadings == null || meterReadings.isEmpty()) {
                log.warn("批量提交电表读数数据为空，社区ID: {}", communityId);
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "表读数数据不能为空");
            }
            
            for (Map<String, Object> reading : meterReadings) {
                Long householdId = Long.valueOf(reading.get("householdId").toString());
                BigDecimal currentReading = new BigDecimal(reading.get("reading").toString());
                LocalDate readingDate = LocalDate.parse(reading.get("readingDate").toString());
                
                submitElectricityMeterReading(householdId, currentReading, readingDate);
            }
            
            log.info("批量提交电表读数完成，社区ID: {}", communityId);
            return true;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("批量提交电表读数失败，社区ID: {}", communityId, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "批量提交电表读数失败");
        }
    }

    @Override
    @GlobalTransactional
    public boolean payElectricityFee(Long billId, BigDecimal paymentAmount, String paymentMethod, LocalDateTime paymentTime) throws Exception {
        log.info("支付电费，账单ID: {}, 支付金额: {}, 支付方式: {}", billId, paymentAmount, paymentMethod);
        
        try {
            // 参数验证
            if (billId == null || paymentAmount == null || paymentMethod == null || paymentTime == null) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "支付参数不能为空");
            }
            
            if (paymentAmount.compareTo(BigDecimal.ZERO) <= 0) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "支付金额必须大于0");
            }

            ElectricityFee fee = electricityFeeMapper.selectById(billId);
            if (fee == null) {
                log.warn("电费记录不存在，ID: {}", billId);
                throw new BusinessException(ResultCode.DATA_NOT_FOUND.getCode(), "电费记录不存在");
            }

            // 检查支付状态
            if (BusinessStatusEnum.PAYMENT_PAID.getCode().equals(fee.getPaymentStatus())) {
                log.warn("电费已支付，账单ID: {}", billId);
                throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "电费已支付，无需重复支付");
            }

            // 转换支付方式：字符串转换为整数值
            Integer paymentMethodCode = convertPaymentMethodToCode(paymentMethod);
            if (paymentMethodCode == null) {
                log.warn("不支持的支付方式: {}, 账单ID: {}", paymentMethod, billId);
                throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "不支持的支付方式: " + paymentMethod);
            }
            
            fee.setPaymentAmount(paymentAmount);
            fee.setPaymentMethod(paymentMethodCode); // 转换为字符串存储
            fee.setPaymentStatus(BusinessStatusEnum.PAYMENT_PAID.getCode()); // 已支付
            fee.setPaymentTime(paymentTime);
            
            // 同步更新已支付金额和未支付金额
            fee.setPaidAmount(paymentAmount); // 已支付金额设置为支付金额
            fee.setUnpaidAmount(BigDecimal.ZERO); // 未支付金额清零

            boolean result = electricityFeeMapper.updateById(fee) > 0;
            log.info("电费支付完成，账单ID: {}, 结果: {}", billId, result);
            return result;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("支付电费失败，账单ID: {}", billId, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "支付电费失败");
        }
    }

    @Override
    public int generateElectricityFee(Long communityId, String billingPeriod, BigDecimal unitPrice) throws Exception {
        log.info("生成电费账单，社区ID: {}, 计费期间: {}, 单价: {}", communityId, billingPeriod, unitPrice);
        
        try {
            // 参数验证
            if (communityId == null || billingPeriod == null || unitPrice == null) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "生成电费账单参数不能为空");
            }
            
            if (unitPrice.compareTo(BigDecimal.ZERO) <= 0) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "电费单价必须大于0");
            }
            
            // fee_type=3 电费，已在SQL层强制，无需外部传递
            int result = electricityFeeMapper.batchGenerateElectricityFee(communityId, billingPeriod, unitPrice);
            log.info("电费账单生成完成，社区ID: {}, 生成数量: {}", communityId, result);
            return result;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("生成电费账单失败，社区ID: {}", communityId, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "生成电费账单失败");
        }
    }

    @Override
    public List<ElectricityFee> getAbnormalUsageRecords(Long communityId, BigDecimal minUsage, BigDecimal maxUsage) throws Exception {
        log.info("查询异常用量记录，社区ID: {}, 最小用量: {}, 最大用量: {}", communityId, minUsage, maxUsage);
        
        try {
            if (minUsage == null || maxUsage == null || minUsage.compareTo(maxUsage) > 0) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "用量范围参数无效");
            }
            
            return electricityFeeMapper.selectAbnormalUsageRecords(communityId, minUsage, maxUsage);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("查询异常用量记录失败，社区ID: {}", communityId, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "查询异常用量记录失败");
        }
    }

    @Override
    public List<ElectricityFee> getUnpaidElectricityFeesByUserId(Long userId) throws Exception {
        log.info("查询用户未缴费电费账单，用户ID: {}", userId);
        
        try {
            if (userId == null) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "用户ID不能为空");
            }
            
            return electricityFeeMapper.selectUnpaidByUserId(userId);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("查询用户未缴费电费账单失败，用户ID: {}", userId, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "查询未缴费账单失败");
        }
    }

    @Override
    public Map<String, Object> getElectricityFeeStatistics(Long communityId, Integer year) throws Exception {
        log.info("获取电费统计信息，社区ID: {}, 年份: {}", communityId, year);
        
        try {
            if (communityId == null || year == null) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "统计参数不能为空");
            }
            
            if (year < 2020 || year > 2030) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "年份参数无效");
            }
            
            return electricityFeeMapper.selectStatistics(communityId, year);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("获取电费统计信息失败，社区ID: {}, 年份: {}", communityId, year, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "获取统计信息失败");
        }
    }
    
    /**
     * 转换支付方式字符串为整数值
     * 
     * @param paymentMethod 支付方式字符串
     * @return 支付方式整数值，如果不支持则返回null
     */
    private Integer convertPaymentMethodToCode(String paymentMethod) {
        if (paymentMethod == null || paymentMethod.trim().isEmpty()) {
            return null;
        }
        
        try {
            PaymentMethodEnum methodEnum = PaymentMethodEnum.fromValue(paymentMethod.trim());
            return methodEnum != null ? methodEnum.getCode() : null;
        } catch (Exception e) {
            log.warn("支付方式转换失败，支付方式: {}", paymentMethod, e);
            return null;
        }
    }
    
    // ==================== 移动端专用方法实现 ====================
    
    @Override
    public PageResult<ElectricityFeeVO> getMyElectricityFees(Integer current, Integer size, 
                                                             Integer paymentStatus, String billingPeriod) throws Exception {
        log.info("开始查询当前用户的电费账单，当前页: {}, 每页大小: {}, 缴费状态: {}, 计费周期: {}", 
                current, size, paymentStatus, billingPeriod);
        
        // 获取当前登录用户ID
        Long currentUserId = SecurityUtils.getCurrentUserId();
        if (currentUserId == null) {
            throw new BusinessException(ResultCode.USER_NOT_LOGIN, "用户未登录");
        }
        
        // 获取用户关联的房户ID集合
        List<Long> householdIds = dataScopeService.getOwnerHouseholdIds(currentUserId);
        if (householdIds.isEmpty()) {
            log.info("用户未关联任何房户，返回空结果，用户ID: {}", currentUserId);
            return PageResult.empty(current, size);
        }
        
        // 构建查询条件
        Page<ElectricityFee> page = new Page<>(current, size);
        QueryWrapper<ElectricityFee> wrapper = new QueryWrapper<>();
        wrapper.in("household_id", householdIds);
        
        if (paymentStatus != null) {
            wrapper.eq("payment_status", paymentStatus);
        }
        if (billingPeriod != null && !billingPeriod.trim().isEmpty()) {
            wrapper.eq("billing_period", billingPeriod);
        }
        
        wrapper.orderByDesc("create_time");
        
        // 执行分页查询
        IPage<ElectricityFee> pageResult = this.page(page, wrapper);
        
        // 转换为VO
        List<ElectricityFeeVO> voList = pageResult.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
        
        // 构建返回结果
        PageResult<ElectricityFeeVO> result = new PageResult<>();
        result.setRecords(voList);
        result.setTotal(pageResult.getTotal());
        result.setCurrent(current);
        result.setSize(size);
        result.setPages((int) pageResult.getPages());
        
        log.info("查询当前用户的电费账单成功，用户ID: {}, 总记录数: {}, 当前页记录数: {}", 
                currentUserId, result.getTotal(), voList.size());
        return result;
    }
    
    @Override
    public ElectricityFeeVO getElectricityFeeDetailForMobile(Long billId, Long userId) throws Exception {
        log.info("开始获取电费详情，账单ID: {}, 用户ID: {}", billId, userId);
        
        if (billId == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "账单ID不能为空");
        }
        
        if (userId == null) {
            throw new BusinessException(ResultCode.USER_NOT_LOGIN, "用户未登录");
        }
        
        // 获取账单信息
        ElectricityFee electricityFee = this.getById(billId);
        if (electricityFee == null) {
            throw new BusinessException(ResultCode.DATA_NOT_FOUND, "账单不存在");
        }
        
        // 验证用户权限
        validateUserPermissionForFee(billId, userId);
        
        // 转换为VO
        ElectricityFeeVO result = convertToVO(electricityFee);
        
        log.info("获取电费详情成功，账单ID: {}, 用户ID: {}", billId, userId);
        return result;
    }
    
    @Override
    public void validateUserPermissionForFee(Long feeId, Long userId) throws Exception {
        log.debug("开始验证用户权限，费用ID: {}, 用户ID: {}", feeId, userId);
        
        if (feeId == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "费用ID不能为空");
        }
        
        if (userId == null) {
            throw new BusinessException(ResultCode.USER_NOT_LOGIN, "用户未登录");
        }
        
        // 获取费用信息
        ElectricityFee electricityFee = this.getById(feeId);
        if (electricityFee == null) {
            throw new BusinessException(ResultCode.DATA_NOT_FOUND, "费用记录不存在");
        }
        
        // 获取用户关联的房户ID集合
        List<Long> householdIds = dataScopeService.getOwnerHouseholdIds(userId);
        
        // 验证用户是否有权限访问该费用记录
        if (!householdIds.contains(electricityFee.getHouseholdId())) {
            throw new BusinessException(ResultCode.PERMISSION_DENIED, "用户无权限访问该费用记录");
        }
        
        log.debug("用户权限验证通过，费用ID: {}, 用户ID: {}", feeId, userId);
    }
    
    /**
     * 转换为VO对象
     */
    private ElectricityFeeVO convertToVO(ElectricityFee electricityFee) {
        if (electricityFee == null) {
            return null;
        }
        
        ElectricityFeeVO vo = new ElectricityFeeVO();
        vo.setId(electricityFee.getId());
        vo.setUserId(electricityFee.getUserId());
        vo.setCommunityId(electricityFee.getCommunityId());
        vo.setBuildingId(electricityFee.getBuildingId());
        vo.setUnitId(electricityFee.getUnitId());
        vo.setHouseholdId(electricityFee.getHouseholdId());
        vo.setBillingPeriod(electricityFee.getBillingPeriod());
        vo.setMeterNo(electricityFee.getMeterNo());
        vo.setPreviousReading(electricityFee.getPreviousReading());
        vo.setCurrentReading(electricityFee.getCurrentReading());
        vo.setUsageAmount(electricityFee.getUsageAmount());
        vo.setUnitPrice(electricityFee.getUnitPrice());
        vo.setAmount(electricityFee.getAmount());
        vo.setPaymentStatus(electricityFee.getPaymentStatus());
        vo.setPaidAmount(electricityFee.getPaidAmount());
        vo.setUnpaidAmount(electricityFee.getUnpaidAmount());
        vo.setPaymentAmount(electricityFee.getPaymentAmount());
        vo.setPaymentTime(electricityFee.getPaymentTime());
        vo.setPaymentMethod(electricityFee.getPaymentMethod());
        vo.setReadingDate(electricityFee.getReadingDate());
        vo.setDueDate(electricityFee.getDueDate());
        vo.setStatus(electricityFee.getStatus());
        vo.setRemark(electricityFee.getRemark());
        vo.setCreateTime(electricityFee.getCreateTime());
        vo.setUpdateTime(electricityFee.getUpdateTime());
        vo.setCreateBy(electricityFee.getCreateBy());
        vo.setUpdateBy(electricityFee.getUpdateBy());
        vo.setVersion(electricityFee.getVersion());
        vo.setDeleted(electricityFee.getDeleted());
        
        // 设置状态名称
        vo.setPaymentStatusName(getPaymentStatusName(electricityFee.getPaymentStatus()));
        vo.setPaymentMethodName(getPaymentMethodName(electricityFee.getPaymentMethod()));
        vo.setStatusName(getStatusName(electricityFee.getStatus()));
        
        return vo;
    }
    
    /**
     * 获取支付状态名称
     */
    private String getPaymentStatusName(Integer paymentStatus) {
        if (paymentStatus == null) {
            return "未知";
        }
        switch (paymentStatus) {
            case 0:
                return "未支付";
            case 1:
                return "已支付";
            case 2:
                return "逾期";
            case 3:
                return "部分支付";
            default:
                return "未知";
        }
    }
    
    /**
     * 获取支付方式名称
     */
    private String getPaymentMethodName(Integer paymentMethod) {
        if (paymentMethod == null) {
            return "未知";
        }
        switch (paymentMethod) {
            case 1:
                return "现金";
            case 2:
                return "微信";
            case 3:
                return "支付宝";
            case 4:
                return "银行卡";
            default:
                return "未知";
        }
    }
    
    /**
     * 获取状态名称
     */
    private String getStatusName(Integer status) {
        if (status == null) {
            return "未知";
        }
        switch (status) {
            case 0:
                return "禁用";
            case 1:
                return "启用";
            default:
                return "未知";
        }
    }
}
